package org.sam.swing;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JSpinner;
import javax.swing.SpinnerDateModel;
import javax.swing.SpinnerModel;
import javax.swing.text.DateFormatter;
import javax.swing.text.DefaultFormatterFactory;

import org.sam.swing.model.SpinnerLocalTimeModel;

/**
 * 自定义的微调控件
 * 主要用来扩展自定义对象的
 * @author sam
 *
 */
public class JSSpinner extends JSpinner {

	private static final long serialVersionUID = 293472918207655190L;

	/**
     * Constructs a spinner for the given model. The spinner has
     * a set of previous/next buttons, and an editor appropriate
     * for the model.
     *
     * @throws NullPointerException if the model is {@code null}
     */
    public JSSpinner(SpinnerModel model) {
       super(model);
    }


    /**
     * Constructs a spinner with an <code>Integer SpinnerNumberModel</code>
     * with initial value 0 and no minimum or maximum limits.
     */
    public JSSpinner() {
        super();
    }
    
	/**
	 * 重写的创建编辑器对象
	 */
	@Override
	protected JComponent createEditor(SpinnerModel model) {
		if(model instanceof SpinnerLocalTimeModel){
			return new LocalTimeEditor(this);
		} 
		
		return super.createEditor(model);
	}

	/**
	 * 创建本地时间的editor
	 * @author sam
	 *
	 */
	public static class LocalTimeEditor extends DefaultEditor{

		/**
		 * 默认构造函数
		 * @param spinner
		 */
		public LocalTimeEditor(JSpinner spinner) {
			this(spinner , getDefaultPattern());
		}

		private static final long serialVersionUID = 4513437173916325099L;
		
		/**
		 * 当前系统默认的格式
		 * @return
		 */
        private static String getDefaultPattern() {
            return "HH:mm:ss";
        }

        /**
         * Construct a <code>JSpinner</code> editor that supports displaying
         * and editing the value of a <code>SpinnerDateModel</code>
         * with a <code>JFormattedTextField</code>.  <code>This</code>
         * <code>DateEditor</code> becomes both a <code>ChangeListener</code>
         * on the spinner and a <code>PropertyChangeListener</code>
         * on the new <code>JFormattedTextField</code>.
         *
         * @param spinner the spinner whose model <code>this</code> editor will monitor
         * @param dateFormatPattern the initial pattern for the
         *     <code>SimpleDateFormat</code> object that's used to display
         *     and parse the value of the text field.
         * @exception IllegalArgumentException if the spinners model is not
         *     an instance of <code>SpinnerDateModel</code>
         *
         * @see #getModel
         * @see #getFormat
         * @see SpinnerDateModel
         * @see java.text.SimpleDateFormat
         */
        public LocalTimeEditor(JSpinner spinner, String dateFormatPattern) {
            this(spinner, DateTimeFormatter.ofPattern(getDefaultPattern(), spinner.getLocale()));
        }

        /**
         * Construct a <code>JSpinner</code> editor that supports displaying
         * and editing the value of a <code>SpinnerDateModel</code>
         * with a <code>JFormattedTextField</code>.  <code>This</code>
         * <code>DateEditor</code> becomes both a <code>ChangeListener</code>
         * on the spinner and a <code>PropertyChangeListener</code>
         * on the new <code>JFormattedTextField</code>.
         *
         * @param spinner the spinner whose model <code>this</code> editor
         *        will monitor
         * @param format <code>DateFormat</code> object that's used to display
         *     and parse the value of the text field.
         * @exception IllegalArgumentException if the spinners model is not
         *     an instance of <code>SpinnerDateModel</code>
         *
         * @see #getModel
         * @see #getFormat
         * @see SpinnerDateModel
         * @see java.text.SimpleDateFormat
         */
        private LocalTimeEditor(JSpinner spinner, DateTimeFormatter format) {
            super(spinner);
            if (!(spinner.getModel() instanceof SpinnerLocalTimeModel)) {
                throw new IllegalArgumentException(
                                 "model not a SpinnerDateModel");
            }

//            SpinnerLocalTimeModel model = (SpinnerLocalTimeModel)spinner.getModel();
//            DateFormatter formatter = new DateEditorFormatter(model, format);
//            DefaultFormatterFactory factory = new DefaultFormatterFactory(
//                                                  formatter);
//            JFormattedTextField ftf = getTextField();
//            ftf.setEditable(true);
//            ftf.setFormatterFactory(factory);
//
//            /* TBD - initializing the column width of the text field
//             * is imprecise and doing it here is tricky because
//             * the developer may configure the formatter later.
//             */
//            try {
//                String maxString = formatter.valueToString(model.getStart());
//                String minString = formatter.valueToString(model.getEnd());
//                ftf.setColumns(Math.max(maxString.length(),
//                                        minString.length()));
//            }
//            catch (ParseException e) {
//                // PENDING: hmuller
//            }
        }

        /**
         * Returns the <code>java.text.SimpleDateFormat</code> object the
         * <code>JFormattedTextField</code> uses to parse and format
         * numbers.
         *
         * @return the value of <code>getTextField().getFormatter().getFormat()</code>.
         * @see #getTextField
         * @see java.text.SimpleDateFormat
         */
        public SimpleDateFormat getFormat() {
            return (SimpleDateFormat)((DateFormatter)(getTextField().getFormatter())).getFormat();
        }


        /**
         * Return our spinner ancestor's <code>SpinnerDateModel</code>.
         *
         * @return <code>getSpinner().getModel()</code>
         * @see #getSpinner
         * @see #getTextField
         */
        public SpinnerDateModel getModel() {
            return (SpinnerDateModel)(getSpinner().getModel());
        }
	}
	
	
	private static class LocalTimeEditorFormatter extends DateFormatter {
		private static final long serialVersionUID = -5223585982519932995L;
		
		private final SpinnerLocalTimeModel model;

		LocalTimeEditorFormatter(SpinnerLocalTimeModel model, DateTimeFormatter format) {
            super(new SimpleDateFormat(format.toString()));
            this.model = model;
        }

        @SuppressWarnings("rawtypes")
		public void setMinimum(Comparable min) {
            model.setStart(min);
        }

        public Comparable<LocalTime> getMinimum() {
            return  model.getStart();
        }

        public void setMaximum(Comparable max) {
            model.setEnd(max);
        }

        public Comparable<LocalTime> getMaximum() {
            return model.getEnd();
        }
    }
}
